﻿using System;
using System.Collections.Generic;

namespace _15csharp
{
    class Program
    {
        static void Main(string[] args)
        {
            Person person = new Person("张三");
            person.Drink("肥宅快乐水");
            person.Drink("气泡水");
            person.Eat();
            ((IEatable)person).Eat();

            Console.WriteLine("----------------------------");

            IEatable obj = new Person("小九");
            obj.Drink("阿萨姆");
            obj.Eat();

            var m = new IEatable.Mouth();

            Console.WriteLine("----------------------------");

            Person p1 = new Person("小叮当");
            p1.Drink("快乐水");
            p1.Drink("矿泉水");
            p1.Drink("气泡水");
            p1.Drink("凉茶");
            var index = 3;
            Console.WriteLine($"{p1.name} - 第 {index + 1} 次喝下了 {p1[index]}");
            index = 4;
            Console.WriteLine($"{p1.name} - 第 {index + 1} 次喝下了 {p1[index]}");

            Console.WriteLine("----------------------------");
            Person p2 = new Person("张无忌");
            p2.OnEatSomething += P2_OnEatSomething;
            p2.Eat();

        }

        private static void P2_OnEatSomething(Person person)
        {
            Console.WriteLine($"{person.name}在偷偷的吃东西！");
        }
    }

    // 接口： Interface 
    // 定义类型的抽象的一系列能力
    //1. 不允许实现具体的方法(但是新语法支持，但是调用必须使用这个接口的声明，而不是类型的声明)
    //2. 新语法中，可以实现具体的方法，同时，不写访问修饰符，依旧可以访问(接口成员会自动成为公共成员)，而类型却不能。
    //2.1 接口中声明的具有具体实现的方法，可以在继承类中实现，可以不实现。方法没有具体实现，继承类中必须实现
    // 2.2 接口中的具体实现的方法，继承类不实现如果调用（见第一条）则输出接口中的实现内容，反之输出继承类中的实现内容
    //3. 接口不能包含实例字段。接口不能包含常量（新的语法中 能够包含常量）
    //3.1 接口不能实现包含实例的构造函数
    //3.2 接口不能带有析构函数，只有类类型才能有
    //3.3 接口能包含类类型
    //4. 接口内的 方法、属性、索引器、事件
    //5. 接口能包含public 、protected 访问修饰符，如果 private 那就需要实现具体的方法
    //6. 从现在的语法特性来看，Interface 和 class 好像没区别了
    //7. 接口类型的字段成员可以是 静态类型,和 class 行为保持一致，但是不支持 static void EatA();
    // 8. 当类类型和 结构类型实现接口时，为接口定义的所有抽象成员提供实现
    //9. 不同于 class ，Interface 可以多继承，class 只能继承一个
    interface IEatable //IEatable =  I(interface) + Eat (吃) + able （具有xxx的能力）
    {
        class Mouth
        {
            public string tooth;
        }
        static int sizea;
  
        static void Eatt() { }

        const int size = 100;        
        /// <summary>
        /// 容量
        /// </summary>
        int Capacity { get; set; }
        int Age { get; }
        // event 关键字，表示事件 ，Action ：无返回值委托，OnEatSomething 声明的事件的字段名
        event Action<Person> OnEatSomething;

        List<string> Drinks { get; set; }
        // 索引器（Indexer） 允许一个对象可以像数组一样使用下标的方式来访问。
        //当您为类定义一个索引器时，该类的行为就会像一个 虚拟数组（virtual array） 一样。
        //您可以使用数组访问运算符[] 来访问该类的的成员(在本例中，通过索引器访问的是 Drinks 集合)。
        string this[int index] { get; }

        /// <summary>吃</summary>
       // 新版本的语法中，接口内可以声明方法
        void Eat()
        {
            Console.WriteLine("666");
        }
        /// <summary>
        /// 喝
        /// </summary>
        /// <param name="name">饮料名称</param>
        void Drink(string name);
        void Output();
    }

    interface Iaa { }
    interface Ibb { }
    //基类实现了接口，那么子类（派生类）也拥有了接口中定义的方法
    class Student : Person, Iaa, Ibb
    {
        public Student(string name) : base(name)
        {
            Drink("ccdd");
            Drinks.Add("aabb");
        }
    }

    interface Icc
    {
        void Eat();
    }
    // 接口的继承，和 class 继承一样的表现行为：能力的继承
    interface Idd : Icc
    {
        void Drink();
    }
    // 100% 实现接口中的抽象成员
    class Dog : Idd
    {
        public void Drink()
        {
        }
        public void Eat()
        {
        }
    }

    // IEateable 接口的继承与实现
    class Person : IEatable
    {
        public List<string> Drinks { get; set; }

        // 接口中事件的实现
        // OnEatSomething = on(当xxx的时候) + Eat （吃）+Something （任意的某些东西）
        public event Action<Person> OnEatSomething;

        // get 、set 、value 是一个套件，用在属性或者索引器
        // 接口中 索引器的实现
        public string this[int index]
        {
            get
            {
                if (Drinks.Count > index)
                {
                    return Drinks[index];
                }
                return "取不到，因为我没有喝这么多种水";
            }
        }


        int capacity;
        // => 是方法表达式主体 ；{} 方法体 ；方法体内只有一行逻辑的他俩可以互相替换
        // 接口的属性的实现
        public int Capacity { get => capacity; set => capacity = value; }
        int age;
        public int Age
        {
            get
            {
                return age;
            }
        }
        public string name;


        public Person(string name)
        {
            this.name = name;
            Drinks = new List<string>();
        }

        public void Drink(string name)
        {
            Drinks.Add(name);
            Console.WriteLine($"{this.name} 喝了{name}");
        }
        public void Eat()
        {
            //Invoke :执行
            // ?.  为空判定
            // 事件的生命周期：声明→执行→监听
            OnEatSomething?.Invoke(this);
            Console.WriteLine("inside person eat");
        }

        // interface 定义的方法实现的时候使用 virtual 来修饰，实现多态，接口跟多态也产生了化学反应
        public virtual void Output()
        {
        }
    }
}
